#pragma once
#ifndef __G_TIMER_H__
#define __G_TIMER_H__

#include "GTypes.h"
#include "GDelegate.h"
#include "GThread/GThread.h"

namespace GUtil
{
	// Tick class for counting elapsed ticks.
	class GTicks
	{
	protected:
		GUInt64			StartTicks;

	public:
						GTicks();
						~GTicks();

		GUInt64			GetElapsedTicks() const;

		void			Reset();

		static GUInt64	QueryTickCount();
		static GUInt64	QueryTickFrequency();

		static G_THREAD_LOCAL GUInt64 TicksPerSecond;

	};

	// Time ratio to represent time precision
	class GTimeRatio
	{
	public:
		static const GTimeRatio Day;
		static const GTimeRatio Hour;
		static const GTimeRatio Minute;
		static const GTimeRatio Second;
		static const GTimeRatio MiliSecond;
		static const GTimeRatio MicroSecond;
		static const GTimeRatio NanoSecond;

		GUInt64 Numerator;
		GUInt64 Denominator;

		GTimeRatio();
		GTimeRatio(const GTimeRatio& Other);
		GTimeRatio(GUInt64 Num, GUInt64 Denom);
		~GTimeRatio();

		operator double () const;

		bool operator == (const GTimeRatio& Other);
		const GTimeRatio& operator = (const GTimeRatio& Other);
	};

	// Representing time with its precision.
	// e.g. 3 seconds or 3 miliseconds.
	class GTimeStamp
	{
	public:
		GUInt64		Count;
		GTimeRatio	Ratio;

					GTimeStamp();
					GTimeStamp(GUInt64 TheCount, const GTimeRatio& TheRatio);
					~GTimeStamp();

					operator double () const;

		double		GetSeconds() const;
	};

	typedef GDelegate<void (float)> GTimerCallback;

	// Timer class that is built on tick counter
	// Can be repeating and have a callback feature
	class GTimer : public GTicks
	{
	private:
		bool				Enabled;
		bool				Reoccur;
		GTimeStamp			Interval;

	public:
		GTimerCallback		Callback;

							GTimer();
							GTimer(bool Enabled, bool Reoccur, const GTimeStamp& Interval);
							~GTimer();

		void				SetReoccur(bool Value);
		bool				GetReoccur() const;

		void				SetEnabled(bool Value);
		bool				GetEnabled() const;

		void				SetInterval(const GTimeStamp& Stamp);
		const GTimeStamp&	GetInterval() const;

		void				Update();
		bool				Chronometer();
		
		double				GetElapsedSeconds();
		GUInt64				GetElapsedTime(const GTimeRatio& Ratio) const;
		static GUInt64		GetElapsedTime(GUInt64 ElapsedTicks, const GTimeRatio& Ratio);

	};

}

#endif